package com.partsoft.dits;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Array;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;



/**
 * 抽象的可配置集成描述符管理器实现。<br/>
 * 实现转换脚本目录检查。
 * @param <E>
 */
@SuppressWarnings("unchecked")
public abstract class AbstractConfigurableDataDescriptorManager<E extends DataEdgeDescriptor>
		extends AbstractConfigurableDescriptorManager<E> implements
		DataDescriptorRegistry<E>, DataDescriptorManager<E>,
		ConfigurableBean, DescriptorDepends<E> {

	private String transformScriptDirectoryLocation;
	
	public AbstractConfigurableDataDescriptorManager() {}
	
	public AbstractConfigurableDataDescriptorManager(String contextConfigLocation, String transformScriptDirectoryLocation) {
		super(contextConfigLocation);
		setTransformScriptDirectoryLocation(transformScriptDirectoryLocation);
	}
	
	public AbstractConfigurableDataDescriptorManager(String contextConfigLocation, String transformScriptDirectoryLocation, boolean createNoExists) {
		super(contextConfigLocation, createNoExists);
		setTransformScriptDirectoryLocation(transformScriptDirectoryLocation);
	}

	
	public String getTransformScriptDirectoryLocation() {
		return transformScriptDirectoryLocation;
	}
	
	public void setTransformScriptDirectoryLocation(String publishConfigBasePath) {
		assertNoInit();
		this.transformScriptDirectoryLocation = publishConfigBasePath;
	}
	
	protected File getTransformScriptDirectory() throws IOException {
		String fname = getTransformScriptDirectoryLocation();
		try {
			Resource drs = getResourceLoader().getResource(fname);
			File f = drs.getFile();
			if (!f.exists()) f.mkdir();
			Assert.isTrue(f.isDirectory(), "Must be directory name");
			return f;
		} catch (Throwable e) {
			throw new IOException(String.format("脚本文件配置目录(%s)不是有效文件目录。", fname), e);
		}
	}
	
	@Override
	public void initContext() {
		Assert.hasText(getTransformScriptDirectoryLocation(), "必须设置脚本文件存储目录参数。");
		synchronized (this) {
			if (isAlreadyInit()) finiContext();
			File tmpeFile = null;
			try {
				File f = getTransformScriptDirectory();
				tmpeFile = new File(getTransformScriptDirectory(), new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()));
				try {
					FileUtils.writeStringToFile(tmpeFile, "test");
				} catch (IOException e) {
					throw new IllegalStateException(String.format("目录(%s)不可写: %s", f.getCanonicalPath(), e.getMessage()), e);
				}
				super.initContext();
			} catch (Throwable e) {
				throw new IllegalArgumentException(e.getMessage(), e);
			} finally {
				FileUtils.deleteQuietly(tmpeFile);
			}
		}
	}
	

	/**
	 * 获得描述符转换脚本相对文件名
	 */
	protected String resolveDescriptorScriptRelativeFileName(E descriptor) {
		return resolveDescriptorIdentifier(descriptor) + ".ftl";
	}
	
	public E getDescriptor(Class<E> clazz, String id) {
		Assert.isTrue(supportDescriptor(clazz));
		return getDescriptor(id);
	}
	
	/**
	 * TODO 需要考虑速度优化问题。
	 */
	public E[] getDescriptors(String messageCode) {
		List<E> returnList = new LinkedList<E>();
		for (E desc : getDescriptorMap().values()) {
			if (ObjectUtils.nullSafeEquals(desc.getMessageCode(), messageCode)) {
				returnList.add(desc);
			}
		}
		Collections.sort(returnList, new Comparator<E>() {
			public int compare(E o1, E o2) {
				return o1.getOrdinal() - o2.getOrdinal();
			}
		});
		E[] returnArray = (E[]) Array.newInstance(getSupportClass(), 0);
		return returnList.toArray(returnArray);
	}
	
	public E[] getDescriptors(String messageCode, DescriptorAccepter<E> accepter) {
		if (accepter == null) return this.getDescriptors(messageCode);
		List<E> returnList = new LinkedList<E>();
		for (E desc : getDescriptorMap().values()) {
			if (ObjectUtils.nullSafeEquals(desc.getMessageCode(), messageCode) && accepter.accept(desc)) {
				returnList.add(desc);
			}
		}
		Collections.sort(returnList, new Comparator<E>() {
			public int compare(E o1, E o2) {
				return o1.getOrdinal() - o2.getOrdinal();
			}
		});
		E[] returnArray = (E[]) Array.newInstance(getSupportClass(), 0); 
		return returnList.toArray(returnArray);
	}
	
	public boolean hasMessageCode(String messageCode) {
		for (E desc : getDescriptorMap().values()) {
			if (ObjectUtils.nullSafeEquals(desc.getMessageCode(), messageCode)) {
				return true;
			}
		}
		return false;
	}
	
	public boolean hasMessageCode(String messageCode, DescriptorAccepter<E> accepter) {
		if (accepter == null) return hasMessageCode(messageCode);
		for (E desc : getDescriptorMap().values()) {
			if (ObjectUtils.nullSafeEquals(desc.getMessageCode(), messageCode) && accepter.accept(desc)) {
				return true;
			}
		}
		return false;
	}
	
	public int countDescriptor(String messageCode) {
		int result = 0;
		for (E desc : getDescriptorMap().values()) {
			if (ObjectUtils.nullSafeEquals(desc.getMessageCode(), messageCode)) {
				result++;
			}
		}
		return result;
	}
	
	public int countDescriptor(String messageCode, DescriptorAccepter<E> accepter) {
		if (accepter == null) return countDescriptor(messageCode);
		int result = 0;
		for (E desc : getDescriptorMap().values()) {
			if (ObjectUtils.nullSafeEquals(desc.getMessageCode(), messageCode) && accepter.accept(desc)) {
				result++;
			}
		}
		return result;
	}

	/**
	 * 提交移除之后的动作
	 * @param descriptor
	 */
	@Override
	protected void postRemoveDescriptor(E descriptor) {
		try {
			FileUtils.deleteQuietly(new File(getTransformScriptDirectory(), resolveDescriptorScriptRelativeFileName(descriptor)));
		} catch (IOException e) {}
	}
	
	/**
	 * 装载一个配置的描述符之前的动作(缺省动作为,加载转换脚本文件)
	 */
	@Override
	protected void beforeLoadConfiguredDescriptor(E descriptor) {
		throw new IllegalStateException(String.format("必须重载此方法，加载(%s)脚本内容", resolveDescriptorScriptRelativeFileName(descriptor)));
	}

}
